package net;

import java.io.*;
import java.net.*;
import java.util.*;

import model.*;

public class TockClient implements TockConstants{
	
	
	private Socket socket;
	private ObjectInputStream incoming;
	private ObjectOutputStream outgoing;
	private UpdatePacket serverReply;
	private String host;
	
	private static boolean MUTEX = false;
	
	
	public TockClient(String host) {
		this.host = host;
	}
	
	public Object getServerReply() {return serverReply;}
	
	//Try connecting to the auction server
	private boolean establishServerConnection() {
		//--- Wait on the mutex
		while (MUTEX) {try {Thread.sleep(500);} catch (InterruptedException e){}}
		try {
			//--- Grab the mutex
			MUTEX = true;
			
			socket = new Socket(InetAddress.getByName(host), SERVER_PORT);
			outgoing = new ObjectOutputStream(socket.getOutputStream());
			incoming = new ObjectInputStream(socket.getInputStream());
			return true;
		} catch (IOException e) {
			System.out.println("CLIENT: Error connecting to server.");
			
			//--- Release the mutex
			MUTEX = false;
			
			return false;
		}
	}
	
	private boolean closeServerConnection() {
		try {
			socket.close();
			
			//--- Release the mutex
			MUTEX = false;
			
			return true;
		} catch (IOException e) {
			System.out.println("CLIENT: Error disconnecting from server.");
			
			//--- Release the mutex
			MUTEX = false;
			
			return false;
		}
	}
	
	public void sendChatPacket(String sender, String message, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending chat packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, message, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending chat packet.");
		} finally {
			closeServerConnection();
		}
	}
			
	public void sendMovePacket(String sender, int card,
					Location pieceSource, Location pieceDest, ArrayList<Location> sevenMoves, int movePacketType, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending move packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, card, pieceSource, pieceDest, sevenMoves, movePacketType, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending move packet.");
		} finally {
			closeServerConnection();
		}
	}	
	
	public void sendRegisterPacket(String sender, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending register packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending register packet.");
		} finally {
			closeServerConnection();
		}
	}
	
	public void sendSitPacket(String sender, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending sit packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, "", TockPacket.SIT, -1, null, null, null, MOVE_PACKET_TYPE_NORMAL, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending sit packet.");
		} finally {
			closeServerConnection();
		}
	}
	
	public void sendStandPacket(String sender, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending stand packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, "", TockPacket.STAND, -1, null, null, null, MOVE_PACKET_TYPE_NORMAL, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending stand packet.");
		} finally {
			closeServerConnection();
		}
	}
	
	public void sendExitPacket(String sender, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending exit packet.");
			return;
		}
		
		TockPacket packet = new TockPacket(sender, 1, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending exit packet.");
		} finally {
			closeServerConnection();
		}
	}
	
	public UpdatePacket sendUpdateRequest(String sender, int gameNum) {
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending update request.");
			return new UpdatePacket(false);
		}
		
		TockPacket packet = new TockPacket(sender, true, gameNum);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending update request.");
		}
		
		// Now wait to see if the registration went through
		try {
			serverReply = (UpdatePacket)incoming.readObject();
		} catch(IOException e) {System.out.println("CLIENT: Error receiving update reply.");}
		catch(ClassNotFoundException e) {System.out.println("CLIENT: UHOH");}
		finally {
			closeServerConnection();
		}
		return serverReply;
	}
	
	public int sendCreateGame(String gameName, int numOfPlayers) {
		Integer serverIntReply = new Integer(-1);
		
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending create game.");
			return -1;
		}
		
		TockPacket packet = new TockPacket("", gameName, TockPacket.CREATE_GAME, numOfPlayers, null, null, null, MOVE_PACKET_TYPE_NORMAL, -1);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending create game.");
		}
		
		// Now wait to see if the registration went through
		try {
			serverIntReply = (Integer)incoming.readObject();
		} catch(IOException e) {System.out.println("CLIENT: Error receiving game number.");}
		catch(ClassNotFoundException e) {System.out.println("CLIENT: UHOH");}
		finally {
			closeServerConnection();
		}
		return serverIntReply.intValue();
	}
	
	public int sendJoinGame(String gameName) {
		Integer serverIntReply = new Integer(-1);
		
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending join game.");
			return -1;
		}
		
		TockPacket packet = new TockPacket("", gameName, TockPacket.JOIN_GAME, -1, null, null, null, MOVE_PACKET_TYPE_NORMAL, -1);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending join game.");
		}
		
		// Now wait to see if the registration went through
		try {
			serverIntReply = (Integer)incoming.readObject();
		} catch(IOException e) {System.out.println("CLIENT: Error receiving game number.");}
		catch(ClassNotFoundException e) {System.out.println("CLIENT: UHOH");}
		finally {
			closeServerConnection();
		}
		return serverIntReply.intValue();
	}
	
	public ArrayList sendGameListRequest() {
		ArrayList serverIntReply = new ArrayList();
		
		if (!establishServerConnection()) {
			System.out.println("CLIENT: Error sending list games.");
			return serverIntReply;
		}
		
		TockPacket packet = new TockPacket("", "", TockPacket.LIST_GAMES, -1, null, null, null, MOVE_PACKET_TYPE_NORMAL, -1);
		
		try {
			outgoing.writeObject(packet);
			outgoing.flush();
		} catch(IOException e) {
			System.out.println("CLIENT: Error sending list games.");
		}
		
		// Now wait to see if the registration went through
		try {
			serverIntReply = (ArrayList)incoming.readObject();
		} catch(IOException e) {System.out.println("CLIENT: Error receiving game list.");}
		catch(ClassNotFoundException e) {System.out.println("CLIENT: UHOH");}
		finally {
			closeServerConnection();
		}
		return serverIntReply;
	}
}